%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Module summary
%%
%% Main authors: Olle
%% Progress: 20%
%%
%% Low-level networking library. 
%%
%% Functions for reading from sockets, parsing from sockets, etc.
%% The functionality is very general, not bound to any specific protocol.
%%
%%%%%%%%%%%%%%%%%%%%%%%

-module(networking).
-compile(export_all).
-define(TCP_OPTIONS, [list, {packet,    0},
                            {active,    false},
                            {reuseaddr, true}]).

% Create a socket in which to listen for connecting users
% 
% Right now this is a sort of hack to simplify the
% large scale testing. When finding a port that's OK to
% use (starting from the number given in Port), 
% we set the Erlang node's environment variable
% of port to the one choosen, so that we can ask the
% database node. 
start(Port) ->
   case gen_tcp:listen(Port, ?TCP_OPTIONS) of
       {ok,PublicSocket} -> application:set_env(db,port,Port),
                            io:fwrite("DB (network): Using port: ~p\n", [Port]),
                            PublicSocket;
       {error,Reason}    -> io:fwrite("networking: "++atom_to_list(Reason)
                                                    ++"; Trying higher port.\n"),
                            start(Port+1)
   end.

%% Keep listening to connecting users
accept(PublicSocket) ->
   {ok,PrivSocket} = gen_tcp:accept(PublicSocket),
   PrivSocket.

%% Grab an unsigned integer from the socket.
%% What endianess does this read from the socket?
get_uint_from_socket(Socket,Len) ->
   Bytes = get_bytes_from_socket(Socket,Len),
   case Bytes of
      error_socket_closed -> error_socket_closed;
      _ ->
         binary:decode_unsigned(list_to_binary(Bytes),big)
   end.

%% Get a certain number of bytes from the socket
get_bytes_from_socket(Socket,Len) ->
    case (Len == 0) or is_atom(Len) of
        true -> [];
        false ->
            case gen_tcp:recv(Socket,Len) of
                {ok,Data} -> Data;
                {error,_} -> error_socket_closed
            end
    end.